package com.swan.security.token;

import com.alibaba.fastjson.JSONObject;
import com.swan.security.auto.config.SecurityConfig;
import com.swan.security.cache.ITokenCache;
import com.swan.security.domain.SecurityUserInfo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

import java.security.Key;
import java.util.Date;
import java.util.Objects;

@Slf4j
public class JwtTokenManager implements InitializingBean {

    @Autowired
    private SecurityConfig securityConfig;

    private Key secretKey;

    @Autowired
    private ITokenCache tokenCache;

    /** 根据用户信息，生成 token
     * @param securityUserInfo 用户信息
     * @return xxx.xxx.xxx
     */
    public String generateToken(SecurityUserInfo securityUserInfo){
        String subject = JSONObject.toJSONString(securityUserInfo);
        Date expireDate = new Date(System.currentTimeMillis() + securityConfig.getToken().getTtl());
        String token = Jwts.builder()
                .setSubject(subject)
                .setIssuedAt(new Date())
                .setExpiration(expireDate)
                .signWith(secretKey, SignatureAlgorithm.HS256)
                .compact();

        // 如果启用校验 token 存在性，则缓存 token
        if (securityConfig.getToken().isCheckTokenExist()) {
            this.tokenCache.set(token, System.currentTimeMillis());
        }
        return token;
    }

    /** 刷新token
     * @param oldToken 原token
     * @return 新的token
     */
    public String refreshToken(String oldToken) {
        SecurityUserInfo securityUserInfo = getUserInfo(oldToken);
        return generateToken(securityUserInfo);
    }

    /** 从 header 中解析 token
     * @param request header 为 Authorization: Bearer xxx.xxx
     * @return token
     */
    public String resolveToken(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }

    /*** 获取 token 中的用户信息
     * @param token
     * @return UserInfo
     */
    public SecurityUserInfo getUserInfo(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(token)
                .getBody();
        String json = claims.getSubject();
        return JSONObject.parseObject(json, SecurityUserInfo.class);
    }

    /** 校验token
     * @param token
     * @return 是否有效
     */
    public boolean validateToken(String token) {

        // 如果开启校验 token 存在，则判断 token 是否存在
        if (securityConfig.getToken().isCheckTokenExist() && Objects.isNull(tokenCache.get(token))) {
            return false;
        }

        try{
            Jwts.parser()
                    .setSigningKey(secretKey)
                    .build()
                    .parseSignedClaims(token);
            return true;
        } catch (Throwable e) {
            log.error("Invalid token: {}", e.getMessage());
        }
        return false;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 解决 yaml 配置明文问题
        this.secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(securityConfig.getToken().getSecret()));
    }

}


